package edu.ssm.campusAssistant.controller;

import edu.ssm.campusAssistant.constant.RspConstants;
import edu.ssm.campusAssistant.utils.bo.JumpBO;
import edu.ssm.campusAssistant.utils.ApplicationUtils;
import edu.ssm.campusAssistant.utils.JumpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 标题:通用跳转控制层
 * 描述:
 *
 * @autho LXF
 * @date 2019/4/7 17:14
 */
@Controller
public class RequestJumpController implements ApplicationContextAware {
    private static Logger logger = LoggerFactory.getLogger(RequestJumpController.class);
    /**
     * spring ApplicationContext
     */
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @RequestMapping(value = "/service/{service}")
    @ResponseBody
    public Object getServiceRoutingNouser(@PathVariable String service, HttpServletRequest request) {
        long start = System.currentTimeMillis();// 请求开始时间
        Object obj = null;
        Map<String, Object> resData = new HashMap<String, Object>();
        try {
            obj = invokeService(service, request);
            // 返回封装数据
            resData = ApplicationUtils.transBean2Map(obj);
        } catch (Exception e) {
            logger.error("请求服务出错：" + e.getMessage());
            resData.put("respCode", RspConstants.RSP_CODE_FAILUR);
            resData.put("respDesc", e.getMessage());
            return resData;
        }
        long end = System.currentTimeMillis();// 结束时间
        long times = end - start;// 消费时间
        logger.info("完整流程执行时间=" + times);
        return resData;
    }

    /**
     * 调用服务
     *
     * @param service
     * @param request
     * @return
     */
    private Object invokeService(String service, HttpServletRequest request) {
        JumpBO jumpBO = JumpUtils.jumpMap.get(service);
        if (jumpBO == null) {
            throw new RuntimeException("未配置请求跳转接口");
        }
        // 请求接口类型
        String serviceType = jumpBO.getServiceName();
        // 请求方法
        String method = jumpBO.getMethodName();
        // 请求headers
        String contentType = request.getContentType();
        if (contentType == null) {
            throw new RuntimeException("请求参数为空");
        }
//        logger.debug("请求contentType--------------" + contentType);
        Object[] objs = null;
//        logger.debug("请求headers--------------" + contentType.toString());
        if (contentType.contains("text/plain") || contentType.contains("application/json") || contentType.contains("text/html")) {
            try {
                objs = ApplicationUtils.parameterConversion(request, serviceType, method);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } else if (contentType.contains("application/x-www-form-urlencoded") || contentType.contains("multipart/form-data")) {
            try {
                request = ApplicationUtils.packageRequestParameters((HttpServletRequest) request);
                objs = ApplicationUtils.parameterConversion2(request, serviceType, method);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } else {
            throw new RuntimeException("暂不支持此种请求方式");
        }
        // 执行对应的方法
        Object returnObj = this.invokeMethod(serviceType, method, objs);
        return returnObj;
    }


    /**
     * 执行对应的方法
     *
     * @param serviceType 接口全路径
     * @param methodName  执行的方法
     * @param obj         方法入参
     * @return
     */
    private Object invokeMethod(String serviceType, String methodName, Object[] obj) {
        Object object = null;
        Class<?> c = null;
        Method method = null;
        try {
            c = Class.forName(serviceType);
        } catch (ClassNotFoundException e) {
            logger.error("接口类型错误", e);
            throw new RuntimeException("接口类型错误", e);
        }
        Object service = applicationContext.getBean(c);
        for (Method m : c.getDeclaredMethods()) {
            if (methodName.equals(m.getName())) {
                method = m;
                break;
            }
        }
        for (Class<?> o : c.getInterfaces()) {
            for (Method m : o.getDeclaredMethods()) {
                if (methodName.equals(m.getName())) {
                    method = m;
                    break;
                }
            }
        }
        try {
            if (obj == null) {
                object = method.invoke(service);
            } else {
                object = method.invoke(service, obj);
            }
        } catch (Exception e) {
            logger.error("执行方法错误！", e);
            throw new RuntimeException("执行方法错误", e);
        }
        return object;
    }
}
